/*
 *  PromptTextHelper.cs
 *  
 *  Provides the capability for controls to show prompt text.
 *  
 *  Copyright (c) 2009, Richard Bao Labs.
 *  
 *  The contents of this file are subject to the Mozilla Public License
 *  Version 1.1 (the "License"); you may not use this file except in
 *  compliance with the License. You may obtain a copy of the License at
 *  
 *  http://www.mozilla.org/MPL/
 *  
 *  Software distributed under the License is distributed on an "AS IS"
 *  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
 *  the License for the specific language governing rights and limitations
 *  under the License.
 *  
 *  The Original Code is RichControlLibrary.
 *  
 *  The Initial Developer of the Original Code is Richard Bao Labs.
 *  All Rights Reserved.
 */

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.ComponentModel;
using System.Drawing;

namespace RichControlLibrary.Internal
{
    internal class PromptTextHelper : IDisposable
    {
        public event EventHandler ValueTextChanged;

        public PromptTextHelper(Control control)
        {
            _control = control;

            _isEmpty = (_control.Text == string.Empty);
            _valueForeColor = _control.ForeColor;
            _valueFont = _control.Font;

            _control.GotFocus += new EventHandler(_control_GotFocus);
            _control.LostFocus += new EventHandler(_control_LostFocus);

            _control.VisibleChanged += delegate { Refresh(true, true); };

            _control.TextChanged += new EventHandler(_control_TextChanged);
            _control.ForeColorChanged += new EventHandler(_control_ForeColorChanged);
            _control.FontChanged += new EventHandler(_control_FontChanged);

            Refresh(true, true);
        }

        ~PromptTextHelper()
        {
            Dispose();
        }

        private Control _control = null;
        protected Control Control
        {
            get { return _control; }
        }

        private bool _isEmpty = true;
        public bool IsEmpty
        {
            get { return _isEmpty; }
        }

        private string _promptText = "Enter text here";
        public string PromptText
        {
            get { return _promptText; }
            set { _promptText = value; }
        }

        public string ValueText
        {
            get
            {
                return _isEmpty ? string.Empty : _control.Text;
            }
            set
            {
                _control.Text = value;
            }
        }

        private bool _showPromptInItalic = true;

        public bool ShowPromptInItalic
        {
            get
            {
                return _showPromptInItalic;
            }
            set
            {
                _showPromptInItalic = value;
                Refresh(true, false);
            }
        }

        private Color _valueForeColor = Control.DefaultForeColor;
        public Color ValueForeColor
        {
            get
            {
                return _valueForeColor;
            }
            set
            {
                _valueForeColor = value;
                Refresh(false, true);
            }
        }

        private Font _valueFont = Control.DefaultFont;
        public Font ValueFont
        {
            get
            {
                return _valueFont;
            }
            set
            {
                _valueFont = value;
                Refresh(false, true);
            }
        }

        private Color _promptForeColor = SystemColors.GrayText;

        public Color PromptForeColor
        {
            get { return _promptForeColor; }
            set { _promptForeColor = value; }
        }

        protected Font PromptFont
        {
            get
            {
                if (_showPromptInItalic)
                {
                    return new Font(_valueFont, _valueFont.Style | FontStyle.Italic);
                }
                else
                {
                    return _valueFont;
                }

            }
        }

        private bool _isPromptDisplaying = false;

        public bool IsPromptDisplaying
        {
            get { return _isPromptDisplaying; }
        }

        private bool _internalChanges = false;

        public void Refresh(bool forcePrompt, bool forceValue)
        {
            _internalChanges = true;

            if (_isEmpty && !_control.Focused)
            {
                if (!(forcePrompt == false && _isPromptDisplaying == true))
                {
                    _control.SuspendLayout();

                    if (!_isPromptDisplaying)
                    {
                        // Save the value format
                        _valueForeColor = _control.ForeColor;
                        _valueFont = _control.Font;
                    }

                    // Display prompt text
                    _control.ForeColor = _promptForeColor;
                    _control.Font = this.PromptFont;
                    _control.Text = _promptText;

                    _control.ResumeLayout();

                    _isPromptDisplaying = true;
                }
            }
            else
            {
                if (!(forceValue == false && _isPromptDisplaying == false))
                {
                    _control.SuspendLayout();

                    // Restore the value format
                    _control.ForeColor = _valueForeColor;
                    _control.Font = _valueFont;

                    // Display value text
                    if (_isEmpty)
                    {
                        _control.Text = "";
                    }

                    _control.ResumeLayout();

                    _isPromptDisplaying = false;
                }
            }

            _internalChanges = false;
        }

        public void CheckParentAppearance()
        {
            if (_valueFont == Control.DefaultFont)
            {
                _valueFont = _control.Parent.Font;
            }

            if (_valueForeColor == Control.DefaultForeColor)
            {
                _valueForeColor = _control.Parent.ForeColor;
            }

            Refresh(true, true);
        }

        private void _control_TextChanged(object sender, EventArgs e)
        {
            if (!_internalChanges)
            {
                _isEmpty = (_control.Text == string.Empty);
                Refresh(false, true);

                OnValueTextChanged(EventArgs.Empty);
            }
        }

        private void _control_ForeColorChanged(object sender, EventArgs e)
        {
            if (!_internalChanges)
            {
                _valueForeColor = _control.ForeColor;
                CheckParentAppearance();
            }
        }

        private void _control_FontChanged(object sender, EventArgs e)
        {
            if (!_internalChanges)
            {
                _valueFont = _control.Font;
                CheckParentAppearance();
            }
        }

        private void _control_GotFocus(object sender, EventArgs e)
        {
            Refresh(true, false);
        }

        private void _control_LostFocus(object sender, EventArgs e)
        {
            Refresh(false, true);
        }

        protected virtual void OnValueTextChanged(EventArgs e)
        {
            if (ValueTextChanged != null)
            {
                EventHandler handler = ValueTextChanged;
                handler(this, e);
            }
        }

        #region IDisposable Members

        public void Dispose()
        {
            _control.GotFocus -= new EventHandler(_control_GotFocus);
            _control.LostFocus -= new EventHandler(_control_LostFocus);

            _control.TextChanged -= new EventHandler(_control_TextChanged);
            _control.ForeColorChanged -= new EventHandler(_control_ForeColorChanged);
            _control.FontChanged -= new EventHandler(_control_FontChanged);

            GC.SuppressFinalize(this);
        }

        #endregion
    }
}
